package com.code.leetcode._202507;

// 43 字符串相乘 中等
public class Multiply {
    /**
     * 给定两个以字符串形式表示的非负整数num1和num2，返回num1和num2的乘积,他们的乘积也表示为字符串形式。
     * 注意：不能使用任何内置的BigInteger库或者直接将输入转化成整数
     * 示例1：输入：num1="2",num2="3"
     * 输出："6"
     * 示例2：输入：num1="123",num2="456"
     * 输出："56088
     * 1<=num1.length,num2.length<=200
     * 只能由数字组成
     * 都不包含任何前导零，除了数字0本身"
     **/
    public static void main(String[] args) {
        Multiply m = new Multiply();
        System.out.println(m.multiply1("123","456"));
    }

    /**做加法
     * 如果num1和num2之一是0.则直接将0作为结果返回即可
     * 如果num1和num2都不是0，则可以通过模拟 竖式乘法 的方法计算乘积。从右往左遍历乘数，将乘数的每一位
     * 与被乘数相乘得到相应的结果，再将每次得到的结果累加。这道题中，被乘数是num1，乘数是num2
     * 需要注意的是,num2除了最低位以外，其余的每一位的运算结果都需要补0
     **/
    public String multiply(String num1, String num2) {
        String ans = "0";
        //如果num1和num2之一是0.则直接将0
        if ("0".equals(num1) || "0".equals(num2)) {
            return ans;
        }
        int m = num1.length(), n = num2.length();
        //需要将num2的每一位数在前一个数的基础上*10*num1
        for (int i = n - 1; i >= 0; i--) {
            StringBuffer curr = new StringBuffer();
            int add = 0;
            //从n-1往前倒推，需要n-1-i个0
            for (int j = n - 1; j > i; j--) {
                curr.append(0);
            }
            //拿到num2的i位对应的数字
            int y = num2.charAt(i) - '0';
            for (int j = m - 1; j >= 0; j--) {
                int x = num1.charAt(j) - '0';
                int product = x * y + add;
                curr.append(product % 10);//取低位的余数
                add = product / 10;//取进位的数字
            }
            if (add != 0) {
                curr.append(add % 10);
            }
            ans = addStrings(ans, curr.reverse().toString());
        }
        return ans;
    }

    public String addStrings(String num1, String num2) {
        int i = num1.length() - 1, j = num2.length() - 1, add = 0;
        StringBuffer ans = new StringBuffer();
        while (i >= 0 || j >= 0 || add != 0) {
            int x = i >= 0 ? num1.charAt(i) - '0' : 0;
            int y = j >= 0 ? num2.charAt(j) - '0' : 0;
            int result = x + y + add;
            ans.append(result % 10);
            add = result / 10;
            i--;
            j--;
        }
        ans.reverse();
        return ans.toString();
    }
    /**做乘法
     * 方法一的做法是从右往左遍历乘数，将乘数的每一位与被乘数相乘得到相应的结果，再将每次得到的结果累加，整个过程
     * 中涉及到较多的字符串相加的操作。如果使用数组代替字符串存储结果，则可以减少对字符串的操作
     * 令m和n分别表示num1金额num2的长度。并且它们均不为0，则num1和num2的乘积的长度位m+n-1或m+n。
     * 简单证明如下：
     * 1、如果num1和num2都取最小值。则num1=10^(m-1),num2=10(n-1),num1*num2=10(m+n-2)，^表示次方
     * 乘积的长度位m+n-1
     * 2、如果num1和num2都取最大值。则num1=10^(m-1),num2=10(n-1),num1*num2=10(m+n)-10^m-10^n+1，
     * 乘积的长度显然小于10^(m+n)且大于10^(m+n-1),因此乘积的长度位m+n。
     * 由于num1和num2的乘积的最大长度为m+n，因此创建长度为m+n的数组ansArr用于存储乘积，对于任意0<=i<=m
     * 和0<=j<=n,num1[i]*num2[j]的结果位于ansArr[i+j+1],如果ansArr[i+j+1]>=10，
     * 则将进位部分加到ansArr[i+j]
     * 最后，将数组ansArr转化成字符串，如果最高位是0则舍弃最高位
     * **/
    public String multiply1(String num1,String num2){
        if ("0".equals(num1) || "0".equals(num2)) {
            return "0";
        }
        int m = num1.length(),n=num2.length();
        int[] ansArr = new int[m+n];
        for (int i = m-1; i >=0 ; i--) {
            int x = num1.charAt(i)-'0';
            for (int j = n-1; j >=0 ; j--) {
                int y = num2.charAt(j)-'0';
                ansArr[i+j+1] += x*y;
            }
        }
        for (int i = m+n-1; i >0 ; i--) {
            ansArr[i-1] += ansArr[i]/10;
            ansArr[i]%=10;
        }
        int index = ansArr[0] ==0?1:0;
        StringBuffer ans = new StringBuffer();
        while (index < m+n){
            ans.append(ansArr[index]);
            index++;
        }
        return ans.toString();
    }

    public String multiply2(String num1, String num2) {
        if (num1.equals("0") || num2.equals("0")) {
            return "0";
        }
        int[] res = new int[num1.length() + num2.length()];
        for (int i = num1.length() - 1; i >= 0; i--) {
            int n1 = num1.charAt(i) - '0';
            for (int j = num2.length() - 1; j >= 0; j--) {
                int n2 = num2.charAt(j) - '0';
                int sum = (res[i + j + 1] + n1 * n2);
                res[i + j + 1] = sum % 10;
                res[i + j] += sum / 10;
            }
        }

        StringBuilder result = new StringBuilder();
        for (int i = 0; i < res.length; i++) {
            if (i == 0 && res[i] == 0) continue;
            result.append(res[i]);
        }
        return result.toString();
    }
}
